using System;
using System.Collections;
using System.Linq;
using MyUtility.Extension;
using UnityEngine;


namespace MyUtility
{
    public class MonoHelper : MonoBehaviour
    {
        public static MonoHelper Ins => _ins;

        public static void CreateMonoHelper()
        {
            CheckInstance();
        }
        
        public static Coroutine StartCo(IEnumerator co)
        {
            return _ins.StartCoroutine(co);
        }
        
        public void AddUpdate(MonoUpdateType type, Action update)
        {
            TryAdd(type, update);
        }

        public void RemoveUpdate(MonoUpdateType type, Action update)
        {
            TryRemove(type, update);
        }

        private void TryAdd(MonoUpdateType type, Action update)
        {
            switch (type)
            {
                case MonoUpdateType.UPDATE:
                    var list1 = _updateActions?.GetInvocationList();
                    if (list1 == null || !list1.Contains(update)) _updateActions += update;
                    break;
                case MonoUpdateType.FIXEDUPDATE:
                    var list2 = _fixedUpdateActions?.GetInvocationList();
                    if (list2==null || !list2.Contains(update)) _fixedUpdateActions += update;
                    break;
                case MonoUpdateType.LATEUPDATE:
                    var list3 = _lateUpdateActions.GetInvocationList();
                    if (list3==null || !list3.Contains(update)) _lateUpdateActions += update;
                    break;
            }
        }
        
        private void TryRemove(MonoUpdateType type, Action update)
        {
            switch (type)
            {
                case MonoUpdateType.UPDATE:
                    var list1 = _updateActions.GetInvocationList();
                    if (list1.Contains(update)) _updateActions -= update;
                    break;
                case MonoUpdateType.FIXEDUPDATE:
                    var list2 = _fixedUpdateActions.GetInvocationList();
                    if (list2.Contains(update)) _fixedUpdateActions -= update;
                    break;
                case MonoUpdateType.LATEUPDATE:
                    var list3 = _lateUpdateActions.GetInvocationList();
                    if (list3.Contains(update)) _lateUpdateActions -= update;
                    break;
            }
        }

        private void Update()
        {
            _updateActions?.Invoke();
        }

        private void FixedUpdate()
        { 
            _fixedUpdateActions?.Invoke();
        }

        private void LateUpdate()
        {
            _lateUpdateActions?.Invoke();
        }

        private static void CheckInstance()
        {
            if (_ins != null) return;

            var parentObj = GameObject.Find("HXGameFramework");
            CreateIns(parentObj);
        }

        private static void CreateIns(GameObject parent)
        {
            if (parent != null)
            {
                _ins = parent.GetComponentInChildren<MonoHelper>();
                if (_ins != null) return;
            }

            var obj = new GameObject(NAME);
            if (parent != null)
            {
                obj.ResetParent(parent);
            }
            else
            {
                DontDestroyOnLoad(obj);
            }
            _ins = obj.AddComponent<MonoHelper>();
        }

        private event Action _updateActions;
        private event Action _lateUpdateActions;
        private event Action _fixedUpdateActions;

        private static MonoHelper _ins;
        private const string NAME = "MonoHelper";
    }

    public enum MonoUpdateType
    {
        UPDATE,
        FIXEDUPDATE,
        LATEUPDATE
    }
}
